package com.dt.app.api.sys.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dt.app.api.sys.mapper.SysUserMapper;
import com.dt.app.api.sys.service.*;
import com.dt.app.common.constant.ConstantCode;
import com.dt.app.common.response.ResultUtil;
import com.dt.app.common.service.CacheService;
import com.dt.app.common.service.RedisService;
import com.dt.app.modules.sys.entities.*;
import com.dt.app.modules.sys.vo.request.SysUserPageRequest;
import com.dt.app.modules.sys.vo.request.SysUserPwdRequest;
import com.dt.app.modules.sys.vo.request.SysUserSaveRequest;
import com.dt.app.modules.sys.vo.response.SysUserCountResponse;
import com.dt.app.modules.sys.vo.response.SysUserPageResponse;
import com.dt.app.modules.sys.vo.response.SysUserResponse;
import org.springframework.beans.BeanUtils;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 系统用户服务实现类
 * @author DT
 * @date 2021/6/2 22:23
 */
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUserEntity> implements SysUserService, UserDetailsService {

    @Resource
    private SysPermissionService sysPermissionService;
    @Resource
    private SysUserRoleService sysUserRoleService;
    @Resource
    private SysRoleService sysRoleService;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private RedisService redisService;
    @Resource
    private CacheService cacheService;
    @Resource
    private ISysCompanyService sysCompanyService;
    @Resource
    private SysDeptService sysDeptService;

    @Override
    public SysUserEntity loadUserByUsername(String username) throws UsernameNotFoundException {
        // 1.查询用户是否存在
        SysUserEntity user = (SysUserEntity) redisService.get(ConstantCode.USER_KEY + username);
        if(ObjectUtils.isEmpty(user)) {
            user = this.baseMapper.selectOne(new QueryWrapper<SysUserEntity>().eq("username",username));
            if(!ObjectUtils.isEmpty(user)) {
                SysCompany sysCompany = sysCompanyService.getById(user.getSysCompanyId());
                user.setCompanyName(sysCompany.getCompanyName());
                user.setLogo(sysCompany.getLogo());
                redisService.set(ConstantCode.USER_KEY + username, user, ConstantCode.REDIS_EXP_TIME);
            }else {
                throw  new UsernameNotFoundException("账号不存在！");
            }
        }
        // 2.查询用户所有的权限
        List<SysPermissionEntity> codeList = (List<SysPermissionEntity>) redisService.get(ConstantCode.PERMISSION_KEY + user.getId());
        if(ObjectUtils.isEmpty(codeList)) {
            codeList = sysPermissionService.getPermissionListByUserId(user.getId());
            if(!codeList.isEmpty()) {
                redisService.set(ConstantCode.PERMISSION_KEY + user.getId(), codeList ,ConstantCode.REDIS_EXP_TIME);
            }
        }
        // 3.获取权限code字段
        String[] strings = codeList.stream().filter(Objects::nonNull).map(SysPermissionEntity::getCode).toArray(String[]::new);
        // 把code转成List<GrantedAuthority>
        List<GrantedAuthority> authorityList = AuthorityUtils.createAuthorityList(strings);
        user.setAuthorities(authorityList);
        // 4.把菜单封装到user
        user.setPermissionList(codeList);
        // 5.设置角色编码
        SysRoleEntity sysRole = sysRoleService.getByUserId(user.getId());
        user.setRoleName(sysRole.getName());
        return user;
    }

    @Override
    @Transactional(readOnly = true)
    public ResultUtil<IPage<SysUserPageResponse>> queryList(SysUserPageRequest request) {
        Page<SysUserPageResponse> page = new Page<>(request.getCurrent(),request.getSize());
        IPage<SysUserPageResponse> list = this.baseMapper.queryList(page,request);
        return ResultUtil.success(list);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultUtil<SysUserSaveRequest> saveUser(SysUserSaveRequest request) {
        this.cacheService.removeUserCache();
        SysUserEntity entity = new SysUserEntity();
        BeanUtils.copyProperties(request,entity);
        SysUserEntity user = this.baseMapper.selectOne(new QueryWrapper<SysUserEntity>().eq("username",entity.getUsername()));
        if(null == user){
            SysDepartmentEntity sysDepartmentEntity= sysDeptService.getById(request.getDeptId());
            if(sysDepartmentEntity!=null)entity.setSysCompanyId(sysDepartmentEntity.getSysCompanyId());
            entity.setPassword(passwordEncoder.encode(entity.getPassword()));
            int insert = this.baseMapper.insert(entity);
            if(insert > 0){
                // 添加角色用户关联信息
                SysUserRoleEntity userRoleEntity = new SysUserRoleEntity();
                userRoleEntity.setUserId(entity.getId());
                userRoleEntity.setRoleId(request.getRoleId());
                sysUserRoleService.save(userRoleEntity);
                return ResultUtil.success(request);
            }
            return ResultUtil.error();
        }else {
            return ResultUtil.error("账号已经存在,请重新输入！");
        }
    }

    @Override
    @Transactional(readOnly = true)
    public ResultUtil<SysUserResponse> getUserById(Long id) {
        SysUserResponse userResponse = this.baseMapper.selectUserById(id);
        SysCompany sysCompany = sysCompanyService.getById(userResponse.getSysCompanyId());
        userResponse.setCompanyName(sysCompany.getCompanyName());
        userResponse.setLogo(sysCompany.getLogo());
        return ResultUtil.success(userResponse);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultUtil<SysUserSaveRequest> updateUser(SysUserSaveRequest request) {
        this.cacheService.removeUserCache();
        SysUserRoleEntity userRoleEntity = new SysUserRoleEntity();
        userRoleEntity.setId(request.getUserRoleId());
        userRoleEntity.setRoleId(request.getRoleId());
        boolean updateById = sysUserRoleService.updateById(userRoleEntity);
        if(updateById){
            SysUserEntity entity = new SysUserEntity();
            BeanUtils.copyProperties(request,entity);
            SysDepartmentEntity sysDepartmentEntity= sysDeptService.getById(request.getDeptId());
            if(sysDepartmentEntity!=null)entity.setSysCompanyId(sysDepartmentEntity.getSysCompanyId());
            int update = this.baseMapper.updateById(entity);
            return update > 0 ? ResultUtil.success() : ResultUtil.error();
        }else {
            return ResultUtil.error();
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultUtil<SysUserEntity> deleteUser(Long id) {
        this.cacheService.removeUserCache();
        int delete = this.baseMapper.deleteById(id);
        return delete > 0 ? ResultUtil.success() : ResultUtil.error();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultUtil<?> updateUserStatus(Long id, Boolean enabled) {
        SysUserEntity entity = this.baseMapper.selectById(id);
        entity.setEnabled(enabled);
        int update = this.baseMapper.updateById(entity);
        return update > 0 ? ResultUtil.success() : ResultUtil.error();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultUtil<Boolean> updatePwd(SysUserPwdRequest request) {
        SysUserEntity sysUser = this.baseMapper.selectOne(new QueryWrapper<SysUserEntity>().lambda().eq(SysUserEntity::getId,request.getId()));
        boolean flag = passwordEncoder.matches(request.getOldPassword(),sysUser.getPassword().trim());
        if(!flag) {
            return ResultUtil.error("旧密码验证错误");
        }else {
            int update = this.baseMapper.updatePwdById(passwordEncoder.encode(request.getNewPassword()),request.getId());
            return update > 0 ? ResultUtil.success() : ResultUtil.error();
        }
    }
    public int updatePwdByAdmin(SysUserPwdRequest request){
        SysUserEntity entity = new SysUserEntity();
        entity.setId(request.getId());
        entity.setPassword(passwordEncoder.encode(request.getNewPassword()));
        //this.updateById(entity);
        return this.baseMapper.updateById(entity);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultUtil<Boolean> updateAvatar(SysUserEntity request) {
        SysUserEntity sysUserEntity = this.baseMapper.selectById(request.getId());
        sysUserEntity.setAvatar(request.getAvatar());
        int update = this.baseMapper.updateById(sysUserEntity);
        return update > 0 ? ResultUtil.success() : ResultUtil.error();
    }

    @Override
    @Transactional(readOnly = true)
    public ResultUtil<Map<String,Object>> queryUserCountByDept() {
        List<SysUserCountResponse> responseList = new ArrayList<>();
        List<SysUserEntity> sysUserEntityList = this.baseMapper.selectList(null);
        Map<String, Long> map = sysUserEntityList.stream()
                .collect(Collectors.groupingBy(SysUserEntity::getDeptName, Collectors.counting()));
        for (Map.Entry<String, Long> entry : map.entrySet()) {
            responseList.add(
                    SysUserCountResponse.builder()
                    .key(entry.getKey())
                    .value(Math.toIntExact(entry.getValue()))
                    .build());
        }
        // 封装数据返回
        if(!responseList.isEmpty()) {
            Map<String,Object> resultMap = new HashMap<>(2);
            List<String> keyList = new ArrayList<>();
            List<Integer> valueList = new ArrayList<>();
            for (SysUserCountResponse response : responseList) {
                keyList.add(response.getKey());
                valueList.add(response.getValue());
            }
            resultMap.put("keyList",keyList);
            resultMap.put("valueList",valueList);
            return ResultUtil.success(resultMap);
        }
        return ResultUtil.success();
    }
}
